
/**
 * @file    
 * @ingroup 
 * @brief   
 *
 *  
 *
 * @author  hang.qi(qihang@sgchip.com)
 * @date    2012/05/01
 * @version 2.0
 */ 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
#include <pthread.h>

//#include <netdb.h>
//#include <signal.h>
//#include <math.h>
//#include <time.h>
//#include <stdarg.h>
//#include <net/if.h>
//#include <netinet/in.h>
//#include <netinet/tcp.h>
//#include <net/if_arp.h>
//#include <arpa/inet.h>
//#include <dirent.h>
//#include <sys/un.h>


//#include <sys/types.h>
//#include <sys/stat.h>
//#include <sys/time.h>
//#include <sys/socket.h> 
//#include <sys/mman.h>
//#include <sys/ioctl.h>

#include "uart.h"
#include "led.h"

pthread_mutex_t                         		g_mutex_uart_para_info[UART_NUM];
arm_uart_para_info_t                    		g_uart_para_info[UART_NUM];



pthread_t 							tid_uart_send;
pthread_t 							tid_uart_recv[UART_NUM];

INT32U 								send_times;

int 									max_fd;
char 								msg[BUFFER_LEN];

int 									thread_para[UART_NUM];
int 									uart_port_end = 0;
int 									uart_port_start = 0;
int 									collect_flag = 0;

int pub_delay_us(long us)
{
		struct timeval tv;
		tv.tv_sec = 0;
		tv.tv_usec = us;
		return select(0,NULL,NULL,NULL,&tv);
}


void perr_exit(const char *s)
{
	perror(s);
	exit(1);
}


ssize_t uart_recvn(int fd, void *vptr, size_t n)
{
	size_t  nleft;
	ssize_t nread;
	char   *ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nread = read(fd, ptr, nleft)) < 0) {
			if (errno == EINTR)
				nread = 0;
			else
				return -1;
		} else if (nread == 0)
			break;

		nleft -= nread;
		ptr += nread;
	}
	return n - nleft;
}


/*send one by one */
ssize_t uart_sendn(int fd, const void *vptr, size_t n)
{
	size_t nleft;
	ssize_t nwritten;
	const char *ptr;

	ptr = vptr;
	nleft = n;
	while (nleft > 0) {
		if ( (nwritten = write(fd, ptr, nleft)) <= 0) {
			if (nwritten < 0 && errno == EINTR)
				nwritten = 0;
			else
				return -1;
		}

		nleft -= nwritten;
		ptr += nwritten;
	}
	return n;
}


ssize_t uart_recv(int fd, INT08U*ptr, size_t nbytes)
{
	ssize_t n;

	//n = read(fd, ptr, nbytes);
	
#if 1
	while( (n = read(fd, ptr, nbytes)) == -1)
	{
		if (errno == EINTR)
			continue;
		else
		{
			//n = -1;
			break;
		}
	}
#endif
	
	return n;
}

ssize_t uart_send(int fd, const void *ptr, size_t nbytes)
{
	ssize_t n;

	while( (n = write(fd, ptr, nbytes)) == -1)
	{
		if (errno == EINTR)
			continue;
		else
		{
			//n = -1;
			break;
		}
	}
	
	return n;
}

/** @brief Uart open device 
 *
 * INT32U uart_open_dev(char *dev)
 *
 *  @param	char *dev: Uart device string 
 *
 *  @return     INT32U
 *  @note       None
 */
INT32U uart_open_dev(char *dev)
{
        INT32U fd;

        fd = open(dev,O_RDWR|O_NOCTTY|O_NONBLOCK);
        if(-1 == fd)
        {
                tcflush(fd, TCOFLUSH);
                perror("Can't Open Serial Port");
                return (UART_EXE_FAILE);
        }
        return fd;
}

/** @brief Save uart para to memory
 *
 * INT32U uart_save_para(INT32U valid,INT32U fd,INT32U baud,INT32U databits,INT32U stopbits,INT32U parity,INT32U num)
 *
 *  @param	INT32U valid: Uart status
 *  @param	INT32U fd: Uart file descriptor
 *  @param	INT32U baud: Uart working baud 
 *  @param	INT32U databits: Uart data bit
 *  @param	INT32U stopbits: Uart stop bit
 *  @param	INT32U parity: Uart parity
 *  @param	INT32U num: Uart com
 *
 *  @return     INT32U
 *  @note       None
 */
INT32U uart_save_para(INT32U valid, INT32U fd, INT32U baud, INT32U databits, INT32U stopbits, INT32U parity, INT32U num)
{

		  pthread_mutex_lock(&g_mutex_uart_para_info[num]);

                memset(&g_uart_para_info[num], 0, sizeof(arm_uart_para_info_t));
				
                	g_uart_para_info[num].valid 		= 	valid;
                	g_uart_para_info[num].com_num 	= 	num;
			g_uart_para_info[num].fd			=	fd;
                	g_uart_para_info[num].baud		=	baud;
                	g_uart_para_info[num].data_bit		=	databits;
                	g_uart_para_info[num].stop_bit		=	stopbits;
                	g_uart_para_info[num].parity_bit	=	parity;

		  pthread_mutex_unlock(&g_mutex_uart_para_info[num]);

                                                printf("/****************** uart[%d] ************************/\n", (int)num);
                                               	printf("* valid = %d\n",g_uart_para_info[num].valid);
                                                printf("* fd = %d\n",(int)g_uart_para_info[num].fd);
                                                printf("* comm_num = %d\n",g_uart_para_info[num].com_num);
                                                printf("* baud = %d\n",(int)g_uart_para_info[num].baud);
                                                printf("* data_len = %d\n",g_uart_para_info[num].data_bit);
                                                printf("* bit_stop = %d\n",g_uart_para_info[num].stop_bit);
                                                printf("* parity = %c\n",g_uart_para_info[num].parity_bit);
                                                printf("/******************************************/\n\n");
        	return 0;
}




/** @brief Uart proper set, databits, stopbits, parity and so on
 *
 * INT32U uart_set_proper(INT32U fd, INT32U databits, INT32U stopbits, INT32U parity)
 *
 *  @param	INT32U fd: Uart file descriptor
 *  @param	INT32U databits: Uart working data bit
 *  @param	INT32U stopbits: Uart working stop bit
 *  @param	INT32U parity: Uart working parity bit
 *
 *  @return     INT32U
 *  @note       None
 */

/*
struct termios
{
	tcflag_t c_iflag; 	//input flags
	tcflag_t c_oflag; 	//output flags
	tcflag_t c_cflag; 	//control flags
	tcflag_t c_lflag; 	//local flags
	cc_t c_cc[NCCS];	//control characters
}
*/
INT32U uart_set_proper(INT32U fd, INT32U baud, INT32U databits, INT32U stopbits, INT32U parity)
{
        struct termios options, oldoptions;
	int tc_ret = 0;

	 tc_ret = tcgetattr(fd, &oldoptions);
        if(tc_ret != 0)
        {
                perror("set_proper");
                return(UART_EXE_FAILE);
        }

        bzero(&options, sizeof(options));

	//set "Local connection" and enable "read"
        options.c_cflag  |=  CLOCAL | CREAD;

	//set "databit"
        options.c_cflag &= ~CSIZE;
        switch (databits)
        {
                case 7:
                        	options.c_cflag |= CS7; break;
                case 8:
                        	options.c_cflag |= CS8; break;
                default:
                       	fprintf(stderr,"Unsupported data bit !\n");
                        	return (UART_EXE_DATABIT_FAILE);
        }
        switch (parity)
        {
                case 'n':
                case 'N':
                        	options.c_cflag &= ~PARENB;
                        	options.c_iflag &= ~INPCK;
                        	break;

                case 'o':
                case 'O':
                        	options.c_cflag |= PARENB;
                        	options.c_cflag |= PARODD;
                        	options.c_iflag |= INPCK;
                        	break;
                case 'e':
                case 'E':
	                     options.c_cflag |= PARENB;
	                     options.c_cflag &= ~PARODD;
	                     options.c_iflag |= INPCK;
	                     break;
                case 'S':
                        	options.c_cflag &= ~PARENB;
                        	options.c_cflag &= ~CSTOPB;
                        	break;

                default:
                        	fprintf(stderr,"Unsupported parity!\n");
                        	return (UART_EXE_PARITY_FAILE);
        }

	switch(baud)
	{
		case 2400:
				cfsetispeed(&options, B2400);
				cfsetospeed(&options, B2400);
				break;
		case 4800:
				cfsetispeed(&options, B4800);
				cfsetospeed(&options, B4800);
				break;
		case 9600:
				cfsetispeed(&options, B9600);
				cfsetospeed(&options, B9600);
				break;
		case 115200:
				cfsetispeed(&options, B115200);
				cfsetospeed(&options, B115200);
				break;
		default:
				cfsetispeed(&options, B115200);
				cfsetospeed(&options, B115200);
				break;
	}

        switch (stopbits)
        {
                case 1:
                        	options.c_cflag &= ~CSTOPB;	break;
                case 2:
                        	options.c_cflag |= CSTOPB; 	break;
                default:
                        	fprintf(stderr,"Unsupported stop bits ! \n");
                        	return (UART_EXE_STOPBIT_FAILE);
        }

        options.c_cc[VMIN] = 0;
        options.c_cc[VTIME] = 0;

        tcflush(fd,TCIFLUSH);
        if ((tcsetattr(fd,TCSANOW,&options)) != 0)
        {
                perror("tcsetattr failed!\n");
                return (UART_EXE_FAILE);
        }
	printf("set uart done!\n");
        return (UART_EXE_OKAY);
}



/** @brief Uart proper set, databits, stopbits, parity and so on
 *
 * INT32U uart_set_para(INT08U com,INT32U baud,INT08U databits,INT08U stopbits,INT08U parity)
 *
 *  @param	INT32U fd: Uart file descriptor
 *  @param	INT32U databits: Uart working data bit
 *  @param	INT32U stopbits: Uart working stop bit
 *  @param	INT32U parity: Uart working parity bit
 *
 *  @return     INT32U
 *  @note       None
 */
INT32U uart_set_para(INT08U com, INT32U baud, INT08U databits, INT08U stopbits, INT08U parity)
{
       INT32U fd;
       INT08U valid = VALID;		 
	INT08U tty[11]="";
	INT32U uart_ret = 0;

	
       get_tty_num(com, tty);


       printf("get_tty_num = %s\n",tty);

       pthread_mutex_lock(&g_mutex_uart_para_info[com]);
	
        fd = uart_open_dev(tty);

        g_uart_para_info[com].fd = fd;

        printf("g_uart_info.uart_para_info[%d].fd = %d\n", com, (int)g_uart_para_info[com].fd);

        pthread_mutex_unlock(&g_mutex_uart_para_info[com]);

        if((uart_ret = uart_set_proper(fd, baud, databits, stopbits, parity))  != UART_EXE_OKAY)
        {
                valid = INVALID;
                return (uart_ret);
        }
	uart_save_para(valid, fd, baud, databits, stopbits, parity, com);
 
        return uart_ret;
}

/** @brief Uart recv task
 *
 * VOID *uart_recv_task(VOID)
 *
 *  @param	VOID
 *
 *  @return     VOID
 *  @note       None
 */
 #define TEST_LED
VOID *uart_recv_task(int *index)
{
        fd_set f_set;

        INT32U nread = 0;
        INT08U buff[UART_RBUFF_LEN] = "";
        INT08U temp[1] = "";
	 int i = 0;
	 int j = 0;
	 int k = 0;
	 struct timeval timeout;						

	int cur_cnt = 0;
	int total_cnt = 0;
	int compose_bit = 0;
	printf("-----------UART[%d] RECV TASK START-------------  \n", *index);
	
        k = *index;
        while(1)
        {
	      	FD_ZERO(&f_set);
		for(i = uart_port_start; i < uart_port_end; i++)
		{
			FD_SET(g_uart_para_info[k].fd, &f_set);
		}
		
              timeout.tv_sec = 0;
              timeout.tv_usec = 1000;
	      	switch(select(g_uart_para_info[k].fd + 1, &f_set, NULL, NULL, &timeout))
              {
              	case -1:			
                          	break;
                    	case 0:	
                          	break;
                    	default:
				 	if (g_uart_para_info[k].valid && FD_ISSET(g_uart_para_info[k].fd, &f_set))
				  	{
				      		while((uart_recv(g_uart_para_info[k].fd, &temp[0], 1)) > 0)
				      		{
                   					buff[nread] = temp[0];
							nread++;
				      		}
						
						printf("\n\nuart[%d] recv_len %d; Compare result:", k, nread);
		#if 1
						if(!memcmp(&buff[0], &msg[0],  UART_RBUFF_LEN))
						{
							printf("Compare Okay!\n");
							switch(k)
							{
								case 0:
										LEDOn(5);
										usleep(200 * 1000);
										LEDOff(5);
										break;
								default:
										LEDOn(k);
										usleep(200 * 1000);
										LEDOff(k);
										break;
							}
						}
						else
						{
							printf("Recv : ");
							for(j = 0; j < nread; j++)
								printf("0x%02x-",buff[j]);
							printf("\n");
						}
	#endif
#if 0
						if(!memcmp(&buff[0], &msg[0],  UART_RBUFF_LEN))
						{
							printf("Compare Okay!\n");
							if(0 == k)
							{
								LEDOn(5);
								usleep(200 * 1000);
								LEDOff(5);
							}
							else
							{
								LEDOn(k);
								usleep(200 * 1000);
								LEDOff(k);
							}
						}
						else
						{
							printf("Recv : ");
							for(j = 0; j < nread; j++)
								printf("0x%02x-",buff[j]);
							printf("\n");
						}
						
#endif
						nread = 0;
						memset(buff, 0x00, BUFFER_LEN);
				  	
				  }
				break;
        	}

	}
}



/* @brief Uart send task
 *
 * VOID *uart_send_task(VOID)
 *
 *  @param	VOID
 *
 *  @return     VOID
 *  @note       None
 */

VOID *uart_send_task(VOID)
{
	INT32U uart_len = 0;
	INT16U msg_len = 0;

	INT08U byi = 0xFF;
	INT32U snd_cnt = 0;
	INT32U total_snd_cnt = 0;
	INT32U i = 0;
	INT32U j = 0;
	INT08U  send_buff[BUFFER_LEN] ;

	for(i =  0; i < BUFFER_LEN; i++)
	{
		send_buff[BUFFER_LEN - i - 1] = i;
	}

	
	printf("----------------------- UART SEND TASK START -------------------\n");

	
	while(1)
       {	
		for(i = uart_port_start; i < uart_port_end; i++)
		{
			if(g_uart_para_info[i].valid)
		  	{
				uart_len = uart_send(g_uart_para_info[i].fd, send_buff, BUFFER_LEN);

				printf("uart[%d] send bytes %d\n", i, uart_len);
		#if 0
				for(j = 0; j < BUFFER_LEN; j++)
				{
					printf("0x%02x -",  send_buff[j]);
				}
				printf("\n");
		#endif
				if(i > uart_port_end - 1)
					printf("\n\n\n");
		  	}
		}
		pub_delay_us(5000000);
	}
}


/** @brief Uart init
 *
 * VOID uart_init(INT32U com)
 *
 *  @param	INT32U com: Com id
 *
 *  @return     VOID
 *  @note       None
 */
VOID uart_init(INT32U com)
{

	INT32U uart_ret = 0;
	memset(&g_uart_para_info[com], 0, sizeof(arm_uart_para_info_t));

        //init mutex
       pthread_mutex_init(&g_mutex_uart_para_info[com],NULL);

        //set default para for uart
#ifndef _ARM_DAEMON_
       uart_ret = uart_set_para(com, BAUD_2400, 8, 1, 'E');
#endif
#ifdef _ARM_DAEMON_
	uart_ret = uart_set_para(com, BAUD_115200, 8, 1, 'O');
#endif
	switch(uart_ret)
	{
		case UART_EXE_OKAY:
			printf("uart[%d] init done and okay!\n", (int)com);

	#ifdef TEST_LED
			LEDOn(com + 1);
	#endif
			break;
		case UART_EXE_FAILE:
			printf("uart[%d] init error!\n", (int)com);return;
		case UART_EXE_BAUD_FAILE:
			printf("uart[%d] init set baud error!\n", (int)com);return;
		case UART_EXE_PARITY_FAILE:
			printf("uart[%d] init set parity err!\n", (int)com);return;
		case UART_EXE_DATABIT_FAILE:
			printf("uart[%d] init set databit err!\n", (int)com);return;
		case UART_EXE_STOPBIT_FAILE:
			printf("uart[%d] init set stopbit err!\n", (int)com);return;
		default:
			break;
	}
       usleep(UART_DELAY);
}

#define		TEST_MODE		"collect"
int main(int argc, char * argv[])
{
	int temp;
	printf("UART MODULE INITIALIZE ...\n");
	int i = 0;

	if(argc > 2)
	{
		printf("Invalid para without getting permmison!\n");
		printf("Usage: ");
		printf("%s <NULL>%s\n", argv[0], TEST_MODE);
		return -1;
	}
	LED_CreateDevice();
	for(i = UART_START; i < UART_NUM; i++)
	{
	  	uart_init(i);
		usleep(1000 * 50);
	}
	for(i = UART_START; i < UART_NUM; i++)
	{
		LEDOff(i + 1); 
		usleep(1000);
	}
	for(i =  0; i < BUFFER_LEN; i++)
	{
		msg[BUFFER_LEN - i - 1] = i;
	}
	GET_MAX_FD(g_uart_para_info, max_fd, i);

	printf("************************************************************\n");
	printf("Max_fd = %d\n", max_fd);
	for(i = UART_START; i < UART_NUM; i++)
	{
		printf("uart[%d]_fd : %d\n", i, g_uart_para_info[i].fd);
	}
	printf("************************************************************\n");
	printf("hello\n");
	if(argv[1] == NULL)
	{
		//uart_port_start = UART_START;
		uart_port_end = 1;
	}
	else
	{
		if(!strcmp(argv[1], "collect"))
			collect_flag = 1;
		else
			uart_port_end = 1;
		printf("hello2\n");
	}
	if(collect_flag == 1)
	{
		uart_port_start = UART_START + 1;
		uart_port_end = UART_NUM;
	}
	
	switch(collect_flag)
	{
		case 1: 
				printf("Collect test mode\n");break;
		default:
				printf("ONU test mode\n");break;
	}
	
#define SEND
#define RECV

#ifdef RECV
	printf("uart_port_start = %d, uart_port_end = %d\n", uart_port_start, uart_port_end);
	for(i = uart_port_start; i < uart_port_end; i++)
	{
		thread_para[i] = i;
    		temp = pthread_create(&tid_uart_recv[i], NULL, (VOID *)uart_recv_task, &thread_para[i]);
    		if(temp == 0)
    		{
        		printf("Uart[%d] recv_pthread create okay!\n", i);
    		}
	}
#endif

#ifdef SEND
    	temp = pthread_create(&tid_uart_send, NULL, (VOID *)uart_send_task, NULL);

    	if(temp == 0)
    	{
        	printf("pthread create send okay!\n");
        	printf("%ld\n", tid_uart_send);
    	}
#endif


#ifdef RECV
	for(i = uart_port_start; i < uart_port_end; i++)
    		pthread_join(tid_uart_recv[i], NULL);
#endif
#ifdef SEND
    	pthread_join(tid_uart_send, NULL);
#endif 		

//#endif
        return 0;
}
 
